Skip to content

[TOC]

JWT 验证

1. 安装包

Microsoft.AspNetCore.Authentication.JwtBearer System.IdentityModel.Tokens.Jwt

注意版本

2. 配置 appsettings.json

json
"Jwt": {
    "Key": "your-very-long-secret-key-at-least-32-characters",
    "Issuer": "my-dev-app",
    "Audience": "my-dev-api",
    "ExpireMinutes": 60 
  },

ExpireMinutes: 分钟的意思 Key :一定要32位数以上

3. 注册 JWT 认证服务(Program.cs要写的)

C
            #region jwt
            // 读取 JWT 配置
            var jwtKey = builder.Configuration["Jwt:Key"];
            var jwtIssuer = builder.Configuration["Jwt:Issuer"];
            var jwtAudience = builder.Configuration["Jwt:Audience"];

            // 添加认证服务
            builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = jwtIssuer,
                        ValidAudience = jwtAudience,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey))
                    };
                });

            builder.Services.AddAuthorization(); // 添加授权服务
            #endregion

注意以上代码要在 var app = builder.Build(); 之前

C
// 添加中间件(顺序重要)
app.UseAuthentication(); // 认证中间件
app.UseAuthorization();  // 授权中间件

4. 生成 JWT 的辅助类

C
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

public static class JwtHelper
{
    public static string GenerateToken(IConfiguration config, string userId, string username, IEnumerable<string> roles)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var claims = new List<Claim>
        {
            new Claim(JwtRegisteredClaimNames.Sub, userId),
            new Claim(ClaimTypes.Name, username),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

        // 添加角色(可多个)
        foreach (var role in roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role));
        }

        var token = new JwtSecurityToken(
            issuer: config["Jwt:Issuer"],
            audience: config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(double.Parse(config["Jwt:ExpireMinutes"])),
            signingCredentials: creds
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

5. 示例

C
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _config;

    public AuthController(IConfiguration config)
    {
        _config = config;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginRequest request)
    {
        // 模拟用户验证(实际应从数据库查询)
        if (request.Username == "admin" && request.Password == "123")
        {
            var token = JwtHelper.GenerateToken(_config, "1", request.Username, new[] { "Admin" });
            return Ok(new { token });
        }

        return Unauthorized("用户名或密码错误");
    }
}

public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

其他需要验证的方法加上

C
[Authorize(Roles = "Admin")]

6. jwt 对应的函数 常用声明类型与 JWT 对应关系

用途JWT 声明.NET ClaimType获取方法
用户 IDsubClaimTypes.NameIdentifierUser.FindFirstValue(ClaimTypes.NameIdentifier)
用户名unique_name 或自定义ClaimTypes.NameUser.Identity.NameUser.FindFirstValue(ClaimTypes.Name)
角色roleClaimTypes.RoleUser.FindAll(ClaimTypes.Role)
邮箱emailClaimTypes.EmailUser.FindFirstValue(ClaimTypes.Email)
JWT IDjtiJwtRegisteredClaimNames.JtiUser.FindFirstValue(JwtRegisteredClaimNames.Jti)

7. 获取当前登录用户信息

C
using System.Security.Claims;

namespace demo1.Uitl.JWT
{
    public static class ClaimsPrincipalExtensions
    {
        /// <summary>
        /// 获取当前登录用户id
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static long GetUserId(this ClaimsPrincipal user)
        {
            var id = user.FindFirstValue(ClaimTypes.NameIdentifier);
            return long.TryParse(id, out long result) ? result : 0;
        }
        /// <summary>
        /// 获取当前登录用户
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public static string GetUserName(this ClaimsPrincipal user)
        {
            return user.Identity?.Name ?? user.FindFirstValue(ClaimTypes.Name);
        }
        /// <summary>
        /// 判断用户是否权限
        /// var claims = new List<Claim>
        //{
        //    // ... 其他声明
        //    new Claim("permission", "article:delete"),
        //    new Claim("permission", "article:edit")
        //};
        /// </summary>
        /// <param name="user"></param>
        /// <param name="permission"></param>
        /// <returns></returns>
        public static bool HasPermission(this ClaimsPrincipal user, string permission)
        {
            return user.HasClaim(c => c.Type == "permission" && c.Value == permission);
        }
    }
}

使用案例

C
User